Skip to content

test discovery 2.0#25760

Merged
eleanorjboyd merged 29 commits intomicrosoft:test-project-supportfrom
eleanorjboyd:instant-eagle-2
Feb 6, 2026
Merged

test discovery 2.0#25760
eleanorjboyd merged 29 commits intomicrosoft:test-project-supportfrom
eleanorjboyd:instant-eagle-2

Conversation

@eleanorjboyd
Copy link
Member

@eleanorjboyd eleanorjboyd commented Feb 3, 2026

Summary

This PR implements project-based test discovery for pytest, enabling multi-project workspace support. When the Python Environments API is available, the extension now discovers Python projects within workspaces and creates separate test tree roots for each project with its own Python environment.

What's New

Project-Based Testing Architecture

  • TestProjectRegistry: Manages the lifecycle of Python test projects, including:

    • Discovering projects via Python Environments API
    • Creating ProjectAdapter instances per workspace
    • Computing nested project relationships for ignore lists
    • Fallback to "legacy" single-adapter mode when API unavailable
  • ProjectAdapter: Interface representing a single Python project with test infrastructure:

    • Project identity (ID, name, URI)
    • Python environment from the environments API
    • Test framework adapters (discovery/execution)
    • Nested project ignore paths

Key Features

  • Multi-project workspaces: Each Python project gets its own test tree root
  • Nested project handling: Parent projects automatically ignore nested child projects via --ignore flags
  • Graceful fallback: Falls back to legacy single-adapter mode if Python Environments API is unavailable
  • Project root path: Python-side get_test_root_path() function returns appropriate root for test tree

Code Improvements

  • Standardized logging prefixes to [test-by-project] across all files
  • Centralized adapter creation via createTestAdapters() helper method
  • Extracted reusable methods for discovery, execution, and file watching

Scope & Limitations

⚠️ Important: unittest is NOT supported in this PR

This PR focuses exclusively on pytest. unittest support for project-based testing will be implemented in a future PR.

Testing

  • Added unit tests for TestProjectRegistry class
  • Added unit tests for Python-side get_test_root_path() function
  • Manual testing with multi-project workspaces

Related Issues

first step in: microsoft/vscode-python-environments#987

eleanorjboyd and others added 18 commits January 8, 2026 11:02
- Created ProjectAdapter and WorkspaceDiscoveryState interfaces
- Added project utility functions (ID generation, scoping, nested project detection)
- Updated PythonResultResolver to support optional projectId parameter
- Modified populateTestTree to create project-scoped test IDs
- Updated TestDiscoveryHandler to handle project-scoped error nodes

Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
- Added project-based state maps (workspaceProjects, vsIdToProject, fileUriToProject, projectToVsIds)
- Implemented discoverWorkspaceProjects() to query Python Environment API
- Created createProjectAdapter() to build ProjectAdapter from PythonProject
- Added createDefaultProject() for backward compatibility
- Imported necessary types from environment API
- Added flag to enable/disable project-based testing

Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
- Modified activate() to check useProjectBasedTesting flag
- Calls discoverWorkspaceProjects() for each workspace when enabled
- Populates workspaceProjects map with discovered projects
- Created activateLegacyWorkspace() for backward compatibility
- Falls back to legacy mode if project discovery fails
- Maintains full backward compatibility with flag disabled

Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
@eleanorjboyd eleanorjboyd self-assigned this Feb 3, 2026
@eleanorjboyd eleanorjboyd added feature-request Request for new features or functionality area-testing labels Feb 3, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements project-based test discovery for pytest, enabling multi-project workspace support where each Python project gets its own test tree root with its own Python environment. When the Python Environments API is available, the extension now discovers Python projects within workspaces and creates separate test adapters for each project.

Changes:

  • Introduces TestProjectRegistry for managing project lifecycle, discovery, and nested project handling
  • Adds ProjectAdapter interface representing individual Python projects with test infrastructure
  • Implements Python-side get_test_root_path() function to support project-scoped test trees
  • Adds comprehensive unit tests for project registry, utilities, and Python-side functions

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/client/testing/testController/controller.ts Refactored activation to support project-based and legacy modes, added project discovery orchestration
src/client/testing/testController/common/testProjectRegistry.ts New registry class managing Python project discovery, adapter creation, and nested project ignore lists
src/client/testing/testController/common/projectAdapter.ts New interface defining structure for project-based test infrastructure
src/client/testing/testController/common/projectUtils.ts Utility functions for project ID generation, display names, and adapter creation
src/client/testing/testController/common/resultResolver.ts Added optional projectId parameter for scoping test IDs to projects
src/client/testing/testController/common/utils.ts Modified populateTestTree to support project-scoped test IDs with separator
src/client/testing/testController/common/types.ts Extracted ITestItemMappings interface, added optional project parameter to ITestDiscoveryAdapter
src/client/testing/testController/common/testDiscoveryHandler.ts Updated error node creation to support project-scoped IDs
src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts Added PROJECT_ROOT_PATH env var and --ignore flags for nested projects
python_files/vscode_pytest/init.py Implemented get_test_root_path() function to return project root or cwd for test tree structure
src/test/testing/testController/controller.unit.test.ts Added tests for controller project-based testing functionality
src/test/testing/testController/common/testProjectRegistry.unit.test.ts Comprehensive tests for TestProjectRegistry class
src/test/testing/testController/common/projectUtils.unit.test.ts Tests for project utility functions (getProjectId, parseVsId, createProjectDisplayName)
python_files/tests/pytestadapter/test_discovery.py Added test_project_root_path_env_var() to verify PROJECT_ROOT_PATH behavior
python_files/tests/pytestadapter/expected_discovery_test_output.py Added expected output for PROJECT_ROOT_PATH test scenario
.github/instructions/testing_feature_area.instructions.md Documented project-based testing architecture and workflow
.github/instructions/testing-workflow.instructions.md Added learning about stubbing after refactoring

@eleanorjboyd eleanorjboyd reopened this Feb 5, 2026
# =====================================================================================
# PROJECT_ROOT_PATH environment variable tests
# These test the project-based testing feature where PROJECT_ROOT_PATH changes
# the test tree root from cwd to the specified project path.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the diagram- outline where the projects are configured in this setup

raise VSCodePytestError(
f"Error occurred while calculating symlink equivalent from node path: {e}"
f"\n SYMLINK_PATH: {SYMLINK_PATH}, \n node path: {node_path}, \n cwd: {_CACHED_CWD if _CACHED_CWD else pathlib.Path.cwd()}"
f"\n SYMLINK_PATH: {SYMLINK_PATH}, \n node path: {node_path}, \n cwd: {_CACHED_CWD or pathlib.Path.cwd()}"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a test which verifies symlinks work with the project based setup? Look at old symlink tests for reference


/**
* Creates test adapters (discovery and execution) for a given test provider.
* Centralizes adapter creation to avoid code duplication across Controller and TestProjectRegistry.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line: Centralizes adapter creation to avoid code duplication across Controller and TestProjectRegistry.


constructor(testController: TestController, testProvider: TestProvider, private workspaceUri: Uri) {
/**
* Optional project ID for scoping test IDs.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in another file the export const PROJECT_ID_SEPARATOR = '@@vsc@@'; should these not be the same?

export class TestProjectRegistry {
/**
* Map of workspace URI -> Map of project ID -> ProjectAdapter
* Project IDs match Python Environments extension's Map<string, PythonProject> keys
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is confusing- clarify this concept better

throw new Error(`No Python environment found for project ${projectId}`);
}

// Create test infrastructure
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clarify test infra per project

/**
* Identifies nested projects and returns ignore paths for parent projects.
*/
private computeNestedProjectIgnores(workspaceUri: Uri): Map<string, string[]> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add time complexity to doc string

* When true, discovers and manages tests per-project using Python Environments API.
* When false, uses legacy single-workspace mode.
*/
private readonly useProjectBasedTesting = true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this feature flag- instead it will operate based on the useEnvExtension variable

project.projectUri,
this.pythonExecFactory,
this.refreshCancellation.token,
undefined, // Interpreter not needed; adapter uses Python Environments API
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the discover test definition to specify this is how it will work (for clarity)

Comment on lines 51 to 53
// NOTE:
// `PythonTestController` calls `vscode.tests.createTestController(...)` in its constructor.
// In unit tests, `vscode` is a mocked module (see `src/test/vscode-mock.ts`) and it does not
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems easier to maybe just add test namespace to the vscode mock module right?

@eleanorjboyd eleanorjboyd changed the base branch from main to test-project-support February 6, 2026 05:01
@eleanorjboyd eleanorjboyd marked this pull request as ready for review February 6, 2026 05:36
@eleanorjboyd eleanorjboyd merged commit 5cc9aac into microsoft:test-project-support Feb 6, 2026
44 checks passed
eleanorjboyd added a commit to eleanorjboyd/vscode-python that referenced this pull request Feb 6, 2026
## Summary

This PR implements **project-based test discovery** for pytest, enabling
multi-project workspace support. When the Python Environments API is
available, the extension now discovers Python projects within workspaces
and creates separate test tree roots for each project with its own
Python environment.

## What's New

### Project-Based Testing Architecture
- **TestProjectRegistry**: Manages the lifecycle of Python test
projects, including:
  - Discovering projects via Python Environments API
  - Creating ProjectAdapter instances per workspace
  - Computing nested project relationships for ignore lists
  - Fallback to "legacy" single-adapter mode when API unavailable

- **ProjectAdapter**: Interface representing a single Python project
with test infrastructure:
  - Project identity (ID, name, URI)
  - Python environment from the environments API
  - Test framework adapters (discovery/execution)
  - Nested project ignore paths

### Key Features
- ✅ **Multi-project workspaces**: Each Python project gets its own test
tree root
- ✅ **Nested project handling**: Parent projects automatically ignore
nested child projects via `--ignore` flags
- ✅ **Graceful fallback**: Falls back to legacy single-adapter mode if
Python Environments API is unavailable
- ✅ **Project root path**: Python-side `get_test_root_path()` function
returns appropriate root for test tree

### Code Improvements
- Standardized logging prefixes to `[test-by-project]` across all files
- Centralized adapter creation via `createTestAdapters()` helper method
- Extracted reusable methods for discovery, execution, and file watching

## Scope & Limitations

> **⚠️ Important: unittest is NOT supported in this PR**
> 
> This PR focuses exclusively on **pytest**. unittest support for
project-based testing will be implemented in a future PR.

## Testing

- Added unit tests for `TestProjectRegistry` class
- Added unit tests for Python-side `get_test_root_path()` function
- Manual testing with multi-project workspaces

## Related Issues
first step in:
microsoft/vscode-python-environments#987

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-testing feature-request Request for new features or functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants